package com.atguigu.gulimall.order.service.impl;

import com.alibaba.fastjson.TypeReference;
import com.atguigu.common.exception.NoStockException;
import com.atguigu.common.to.mq.OrderTo;
import com.atguigu.common.to.mq.SeckillOrderTo;
import com.atguigu.common.utils.R;
import com.atguigu.common.vo.MemberResponseVo;
import com.atguigu.gulimall.order.constant.OrderConstant;
import com.atguigu.gulimall.order.entity.OrderItemEntity;
import com.atguigu.gulimall.order.entity.PaymentInfoEntity;
import com.atguigu.gulimall.order.enume.OrderStatusEnum;
import com.atguigu.gulimall.order.feign.CartFeignService;
import com.atguigu.gulimall.order.feign.MemberFeignService;
import com.atguigu.gulimall.order.feign.ProductFeignService;
import com.atguigu.gulimall.order.feign.WmsFeignService;
import com.atguigu.gulimall.order.interceptor.LoginUserInterceptor;
import com.atguigu.gulimall.order.service.OrderItemService;
import com.atguigu.gulimall.order.service.PaymentInfoService;
import com.atguigu.gulimall.order.to.OrderCreateTo;
import com.atguigu.gulimall.order.vo.*;
import com.baomidou.mybatisplus.core.toolkit.IdWorker;
import org.springframework.amqp.rabbit.core.RabbitTemplate;
import org.springframework.aop.framework.AopContext;
import org.springframework.beans.BeanUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.redis.core.StringRedisTemplate;
import org.springframework.data.redis.core.script.DefaultRedisScript;
import org.springframework.stereotype.Service;

import java.math.BigDecimal;
import java.util.*;
import java.util.concurrent.CompletableFuture;
import java.util.concurrent.ExecutionException;
import java.util.concurrent.ThreadPoolExecutor;
import java.util.concurrent.TimeUnit;
import java.util.stream.Collectors;

import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.baomidou.mybatisplus.core.metadata.IPage;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.atguigu.common.utils.PageUtils;
import com.atguigu.common.utils.Query;

import com.atguigu.gulimall.order.dao.OrderDao;
import com.atguigu.gulimall.order.entity.OrderEntity;
import com.atguigu.gulimall.order.service.OrderService;
import org.springframework.transaction.annotation.Propagation;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.util.StringUtils;
import org.springframework.web.context.request.RequestAttributes;
import org.springframework.web.context.request.RequestContextHolder;
/**
 * 订单
 */
@Service("orderService")
public class OrderServiceImpl extends ServiceImpl<OrderDao, OrderEntity> implements OrderService {
    @Autowired MemberFeignService memberFeignService;
    @Autowired CartFeignService cartFeignService;
    @Autowired ThreadPoolExecutor executor;
    @Autowired WmsFeignService wmsFeignService;
    @Autowired StringRedisTemplate stringRedisTemplate;
    @Autowired ProductFeignService productFeignService;
    @Autowired OrderItemService orderItemService;
    @Autowired RabbitTemplate rabbitTemplate;
    @Autowired PaymentInfoService paymentInfoService;
    private ThreadLocal<OrderSubmitVo> confirmVoThreadLocal = new ThreadLocal<>();

    /**
     * 创建订单(秒杀)
     */
    @Override
    public void createSeckillOrder(SeckillOrderTo seckillOrder) {
        //1、保存订单信息
        OrderEntity orderEntity = new OrderEntity();
        orderEntity.setOrderSn(seckillOrder.getOrderSn());    //订单号
        orderEntity.setMemberId(seckillOrder.getMemberId());    //会员id
        orderEntity.setStatus(OrderStatusEnum.CREATE_NEW.getCode());    //订单状态: CREATE_NEW(0, "待付款")
        //                                     秒杀价格          乘以                                秒杀数量
        BigDecimal multiply = seckillOrder.getSeckillPrice().multiply(new BigDecimal("" + seckillOrder.getNum()));
        orderEntity.setPayAmount(multiply);    //秒杀价格
        this.save(orderEntity);

        //2、保存订单项信息
        OrderItemEntity entity = new OrderItemEntity();
        entity.setOrderSn(seckillOrder.getOrderSn());    //订单号
        entity.setRealAmount(multiply);    //该商品经过优惠后的分解金额
        entity.setSkuQuantity(seckillOrder.getNum());    //商品购买的数量
        orderItemService.save(entity);
    }


    /**
     * 处理支付成功返回的结果
     */
    @Override
    public String handlePayResult(PayAsyncVo vo) {
        //1、保存交易流水信息
        PaymentInfoEntity infoEntity = new PaymentInfoEntity();
        infoEntity.setAlipayTradeNo(vo.getTrade_no());    //支付宝交易流水号
        infoEntity.setOrderSn(vo.getOut_trade_no());    //订单号（对外业务号）
        infoEntity.setPaymentStatus(vo.getTrade_status());    //支付状态
        infoEntity.setCallbackTime(vo.getNotify_time());    //回调时间
        paymentInfoService.save(infoEntity);

        //2、修改订单状态信息            TRADE_SUCCESS：交易成功                        TRADE_FINISHED：交易已完成
        if (vo.getTrade_status().equals("TRADE_SUCCESS") || vo.getTrade_status().equals("TRADE_FINISHED")) {
            //支付成功状态
            String outTradeNo = vo.getOut_trade_no();    //订单号
            //调用《根据 订单号 修改订单状态》方法
            baseMapper.updateOrderStatus(outTradeNo, OrderStatusEnum.PAYED.getCode());    //PAYED(1, "已付款")
        }
        return "success";
    }


    /**
     * 查询当前用户的所有订单 以及 所有订单项的数据
     */
    @Override
    public PageUtils queryPageWithItem(Map<String, Object> params) {
        //1、从拦截器里面获取当前登录的用户信息
        MemberResponseVo memberResponseVo = LoginUserInterceptor.loginUser.get();
        //2、根据 会员id 查询所有订单
        IPage<OrderEntity> page = this.page(
                new Query<OrderEntity>().getPage(params),
                new QueryWrapper<OrderEntity>().eq("member_id", memberResponseVo.getId()).orderByDesc("id"));

        List<OrderEntity> orderEntities = page.getRecords().stream().map(order -> {
            //3、根据 订单号 查询每个订单的订单项
            List<OrderItemEntity> entities = orderItemService.list(
                    new QueryWrapper<OrderItemEntity>().eq("order_sn", order.getOrderSn()));
            order.setItemEntities(entities);    //所有的订单项信息
            return order;
        }).collect(Collectors.toList());
        page.setRecords(orderEntities);    //设置订单数据
        return new PageUtils(page);
    }

    /**
     * 根据 订单号 获取支付页面需要的订单数据
     */
    @Override
    public PayVo getOrderPay(String orderSn) {
        //1、查询订单的详细信息
        PayVo payVo = new PayVo();
        OrderEntity order = getOrderByOrderSn(orderSn);    //调用《根据 订单号 查询订单的详细信息》方法

        //2、应付总额设置为两位小数，因为数据库表保留4位小数，支付页面只能2位小数否则会报错
        BigDecimal bigDecimal = order.getPayAmount().setScale(2, BigDecimal.ROUND_UP);    //ROUND_UP：四舍五入
        payVo.setTotal_amount(bigDecimal.toString());    //付款金额，必填
        payVo.setOut_trade_no(order.getOrderSn());    //商户订单号，必填

        //3、根据 订单号 查询所有订单项信息
        List<OrderItemEntity> order_sn = orderItemService.list(new QueryWrapper<OrderItemEntity>().eq("order_sn", orderSn));
        OrderItemEntity entity = order_sn.get(0);    //拿第一个订单项
        payVo.setSubject(entity.getSkuName());    //订单名称，必填
        payVo.setBody(entity.getSkuAttrsVals());    //商品描述，可空
        return payVo;
    }


    /**
     * 根据 订单号 查询订单的详细信息
     */
    @Override
    public OrderEntity getOrderByOrderSn(String orderSn) {
        OrderEntity orderEntity = this.getOne(new QueryWrapper<OrderEntity>().eq("order_sn", orderSn));
        return orderEntity;
    }


    /**
     * 关闭订单
     */
    @Override
    public void closeOrder(OrderEntity entity) {
        //1、查询当前订单的最新状态
        OrderEntity orderEntity = this.getById(entity.getId());
        if (orderEntity.getStatus() == OrderStatusEnum.CREATE_NEW.getCode()){    //CREATE_NEW(0, "待付款")
            //2、关单
            OrderEntity update = new OrderEntity();
            update.setId(entity.getId());
            update.setStatus(OrderStatusEnum.CANCLED.getCode());    //CANCLED(4, "已取消")
            this.updateById(update);
            OrderTo orderTo = new OrderTo();
            BeanUtils.copyProperties(orderEntity, orderTo);
            //3、TODO 发给 MQ 一个
            try{
                //保证消息一定会发送出去，每个消息都可以做好日志记录 (给数据库保存每个消息的详细信息)
                rabbitTemplate.convertAndSend("order-event-exchange", "order.dead.other", orderTo);
            }catch (Exception e){
                //定期扫描数据库，将失败的消息在发送一遍
            }
        }
    }


    /**
     * 下单功能
     */
    @Override
    @Transactional    //添加事务，保证数据的一致性
//    @GlobalTransactional    //开启分布式事务功能
    public SubmitOrderResponseVo submitOrder(OrderSubmitVo submitVo) {
        confirmVoThreadLocal.set(submitVo);    //把页面传过来的所有数据放到 ThreadLocal 中
        SubmitOrderResponseVo responseVo = new SubmitOrderResponseVo();
        MemberResponseVo memberResponseVo = LoginUserInterceptor.loginUser.get();
        responseVo.setCode(0);
        //1、验证令牌【令牌的对比和删除必须保证原子性】
        //lue 脚本，含义：如果 get 的令牌和页面传过来的令牌一样，就删除令牌并且返回 1，否则返回 0
        String script = "if redis.call('get', KEYS[1]) == ARGV[1] then return redis.call('del', KEYS[1]) else return 0 end";
        String orderToken = submitVo.getOrderToken();
        //2、原子验证令牌和删除令牌
        Long result = stringRedisTemplate.execute(new DefaultRedisScript<>(script, Long.class),    //execute 可以执行脚本
                Arrays.asList(OrderConstant.USER_ORDER_TOKEN_PREFIX + memberResponseVo.getId()), orderToken); //把key 和 value放到list
        if (result == 0L) {
            //令牌验证失败
            responseVo.setCode(1);    //1: "订单信息过期, 请刷新后再次提交！"
            return responseVo;
        } else {
            //令牌验证成功，下单：去创建订单 验证令牌 核算价格 锁定库存
            //1、创建订单，订单项等信息
            OrderCreateTo order = createOrder();    //调用《生成订单》方法
            //2、验价
            BigDecimal payAmount = order.getOrder().getPayAmount();    //应付总额 (订单总额)
            BigDecimal payPrice = submitVo.getPayPrice();    //应付价格，验价 (页面传过来的)

            //Math.abs：求绝对值，如果 应付总额 (订单总额) 减去 应付价格，验价 (页面传过来的)，的绝对值的范围小于0.01
            if (Math.abs(payAmount.subtract(payPrice).doubleValue()) < 0.01){
                //3、金额对比成功
                //3.1 保存订单
                saveOrder(order);    //调用《保存订单数据》方法

                //3.2 库存锁定, 只要有异常回滚订单数据。订单号，订单项信息（skuId, skuName, num）
                WareSkuLockVo wareSkuLockVo = new WareSkuLockVo();
                wareSkuLockVo.setOrderSn(order.getOrder().getOrderSn());    //订单号
                //处理所有订单项
                List<OrderItemVo> orderItemVos = order.getOrderItems().stream().map(item -> {
                    OrderItemVo orderItemVo = new OrderItemVo();
                    orderItemVo.setSkuId(item.getSkuId());
                    orderItemVo.setCount(item.getSkuQuantity());
                    orderItemVo.setTitle(item.getSkuName());
                    return orderItemVo;
                }).collect(Collectors.toList());
                wareSkuLockVo.setLocks(orderItemVos);    //需要锁住的所有库存信息
                //锁定订单库存
                R r = wmsFeignService.orderLockStock(wareSkuLockVo);    //远程调用《为当前订单锁定库存》方法
                if (r.getCode() == 0){
                    //锁成功了
                    responseVo.setOrder(order.getOrder());
                    //int i = 10 / 0;
                    //TODO 订单创建成功，发送消息给 MQ
                    rabbitTemplate.convertAndSend("order-event-exchange", "order.delay.order", order.getOrder());
                    return responseVo;
                }else {
                    //锁定失败
                    responseVo.setCode(3);    //3: "库存锁定失败, 商品库存不足！"
                    throw new NoStockException((String) r.get("msg"));
                }
            }else {
                //4、金额对比失败
                responseVo.setCode(2);    //2: "订单中的商品价格发生变化, 请刷新后再次提交！"
                return responseVo;
            }}}


    /**
     * 生成订单
     */
    public OrderCreateTo createOrder(){
        OrderCreateTo createTo = new OrderCreateTo();
        //1、生成一个订单号(时间 + id类型的)
        String orderSn = IdWorker.getTimeId();
        //2、创建订单
        OrderEntity orderEntity = buildOrder(orderSn);    //调用《根据订单号创建订单》方法
        createTo.setOrder(orderEntity);    //设置订单
        //3、获取所有的订单项
        List<OrderItemEntity> itemEntities = buildOrderItems(orderSn);    //调用《构建所有订单项数据》方法
        createTo.setOrderItems(itemEntities);    //设置订单项
        //4、计算价格、积分等相关
        computePrice(orderEntity, itemEntities);    //调用《计算所有订单项的价格、积分》方法
        return createTo;
    }

    /**
     * 根据订单号创建订单
     */
    private OrderEntity buildOrder(String orderSn) {
        //1、从拦截器中获取用户信息
        MemberResponseVo memberResponseVo = LoginUserInterceptor.loginUser.get();
        OrderEntity orderEntity = new OrderEntity();
        orderEntity.setOrderSn(orderSn);    //订单号
        orderEntity.setMemberId(memberResponseVo.getId());    //会员id

        //2、从 confirmVoThreadLocal 获取页面传过来的所有数据
        OrderSubmitVo orderSubmitVo = confirmVoThreadLocal.get();

        //3、远程调用《根据地址 id 查询运费》方法
        R r = wmsFeignService.getFare(orderSubmitVo.getAddrId());
        FareVo fareResp = r.getData(new TypeReference<FareVo>() {});
        //设置运费信息
        orderEntity.setFreightAmount(fareResp.getFare());   //运费金额
        //设置收货人信息
        orderEntity.setReceiverCity(fareResp.getAddress().getCity());    //城市
        orderEntity.setReceiverDetailAddress(fareResp.getAddress().getDetailAddress());    //详细地址
        orderEntity.setReceiverName(fareResp.getAddress().getName());    //收货人姓名
        orderEntity.setReceiverPhone(fareResp.getAddress().getPhone());    //收货人电话
        orderEntity.setReceiverPostCode(fareResp.getAddress().getPostCode());    //收货人邮编
        orderEntity.setReceiverRegion(fareResp.getAddress().getRegion());    //区

        //设置订单的相关状态信息
        orderEntity.setStatus(OrderStatusEnum.CREATE_NEW.getCode());    //CREATE_NEW(0, "待付款")
        orderEntity.setAutoConfirmDay(7);    //设置自动确认日期
        return orderEntity;
    }

    /**
     * 构建所有订单项数据
     */
    private List<OrderItemEntity> buildOrderItems(String orderSn) {
        //1、远程调用《获取用户购物车里所有选中的购物项的数据》方法
        List<OrderItemVo> currentUserCartItems = cartFeignService.getCurrentUserCartItems();
        if (currentUserCartItems != null && currentUserCartItems.size() > 0) {
            List<OrderItemEntity> itemEntities = currentUserCartItems.stream().map(cartItem -> {
                //2、查询每一个订单项
                OrderItemEntity itemEntity = buildOrderItem(cartItem);    //调用《构建某一个订单项》方法
                itemEntity.setOrderSn(orderSn);    //订单号
                return itemEntity;
            }).collect(Collectors.toList());
            return itemEntities;
        }
        return null;
    }

    /**
     * 构建某一个订单项
     */
    private OrderItemEntity buildOrderItem(OrderItemVo cartItem) {
        OrderItemEntity orderItemEntity = new OrderItemEntity();
        //1、订单信息 订单号
        //2、spu信息
        Long skuId = cartItem.getSkuId();
        R r = productFeignService.getSpuInfoBySkuId(skuId);    //远程调用《根据 skuId 查询 spu 信息》方法
        SpuInfoVo data = r.getData(new TypeReference<SpuInfoVo>(){});

        orderItemEntity.setSpuId(data.getId());
        orderItemEntity.setSpuBrand(data.getBrandId().toString());    //品牌
        orderItemEntity.setSpuName(data.getSpuName());    //sku名称
        orderItemEntity.setCategoryId(data.getCatalogId());    //分类id

        //3、sku信息
        orderItemEntity.setSkuId(cartItem.getSkuId());
        orderItemEntity.setSkuName(cartItem.getTitle());    //商品sku名字
        orderItemEntity.setSkuPic(cartItem.getImage());    //商品sku图片
        orderItemEntity.setSkuPrice(cartItem.getPrice());    //商品sku价格
        String skuAttrs = StringUtils.collectionToDelimitedString(cartItem.getSkuAttr(), ";");    //将集合转换成字符串，以";"分隔开
        orderItemEntity.setSkuAttrsVals(skuAttrs);    //商品销售属性组合（JSON）
        orderItemEntity.setSkuQuantity(cartItem.getCount());    //商品购买的数量

        //4、优惠信息 [不做]
        //5、积分信息
        //赠送成长值                           价格            乘以                         数量
        orderItemEntity.setGiftGrowth(cartItem.getPrice().multiply(new BigDecimal(cartItem.getCount().toString())).intValue());
        //赠送积分                                  价格           乘以                         数量
        orderItemEntity.setGiftIntegration(cartItem.getPrice().multiply(new BigDecimal(cartItem.getCount().toString())).intValue());

        //6、订单项的价格信息
        orderItemEntity.setPromotionAmount(new BigDecimal("0"));    //商品促销分解金额
        orderItemEntity.setIntegrationAmount(new BigDecimal("0"));    //积分优惠分解金额
        orderItemEntity.setCouponAmount(new BigDecimal("0"));    //优惠券优惠分解金额

        //7、当前订单项的实际金额          商品sku价格            乘以                              商品购买的数量
        BigDecimal origin = orderItemEntity.getSkuPrice().multiply(new BigDecimal(orderItemEntity.getSkuQuantity().toString()));

        //8、实际金额 (origin) 减去各种优惠后的价格
        BigDecimal subtract = origin
                .subtract(orderItemEntity.getCouponAmount())    //减去 优惠券优惠分解金额
                .subtract(orderItemEntity.getIntegrationAmount())    //减去 积分优惠分解金额
                .subtract(orderItemEntity.getPromotionAmount());    //减去 商品促销分解金额

        //9、当前订单项的应付总额
        orderItemEntity.setRealAmount(subtract);    //该商品经过优惠后的分解金额
        return orderItemEntity;
    }

    /**
     * 计算所有订单项的价格、积分
     */
    private void computePrice(OrderEntity orderEntity, List<OrderItemEntity> itemEntities) {
        BigDecimal total = new BigDecimal("0.0");    //该商品经过优惠后的分解金额
        BigDecimal coupon = new BigDecimal("0.0");    //优惠券优惠分解金额
        BigDecimal integration = new BigDecimal("0.0");    //积分优惠分解金额
        BigDecimal promotion = new BigDecimal("0.0");    //商品促销分解金额
        BigDecimal gift = new BigDecimal("0.0");    //赠送积分
        BigDecimal growth = new BigDecimal("0.0");    //赠送成长值

        //1、订单的总额，叠加每一个订单项的总额信息。
        for (OrderItemEntity entity : itemEntities) {
            coupon = coupon.add(entity.getCouponAmount());
            integration = integration.add(entity.getIntegrationAmount());
            promotion = promotion.add(entity.getPromotionAmount());
            total = total.add(entity.getRealAmount());
            gift = gift.add(new BigDecimal(entity.getGiftIntegration().toString()));
            growth = growth.add(new BigDecimal(entity.getGiftGrowth().toString()));
        }

        //2、订单价格相关
        orderEntity.setTotalAmount(total);    //订单总额

        //3、应付金额
        orderEntity.setPayAmount(total.add(orderEntity.getFreightAmount()));    //应付总额 = 订单总额 + 运费金额
        orderEntity.setPromotionAmount(promotion);    //促销优化金额（促销价、满减、阶梯价）
        orderEntity.setIntegrationAmount(integration);    //积分抵扣金额
        orderEntity.setCouponAmount(coupon);    //优惠券抵扣金额

        //4、设置积分信息
        orderEntity.setIntegration(gift.intValue());    //可以获得的积分
        orderEntity.setGrowth(growth.intValue());    //可以获得的成长值

        //5、设置删除状态 0未删除
        orderEntity.setDeleteStatus(0);    //删除状态【0->未删除；1->已删除】
    }

    /**
     * 保存订单数据
     */
    private void saveOrder(OrderCreateTo order) {
        OrderEntity orderEntity = order.getOrder();    //获取订单
        orderEntity.setModifyTime(new Date());    //修改时间
        this.save(orderEntity);    //保存订单
        List<OrderItemEntity> orderItems = order.getOrderItems();    //获取订单的所有订单项
        orderItemService.saveBatch(orderItems);    //保存所有订单项
    }

    /**
     * 给订单需要页返回需要的数据
     */
    @Override
    public OrderConfirmVo confirmOrder() throws ExecutionException, InterruptedException {
        OrderConfirmVo confirmVo = new OrderConfirmVo();
        //1、从拦截器的 ThreadLocal 中获取用户信息
        MemberResponseVo memberResponseVo = LoginUserInterceptor.loginUser.get();

        //① 获取之前的请求
        RequestAttributes requestAttributes = RequestContextHolder.getRequestAttributes();

        CompletableFuture<Void> getAddressFuture = CompletableFuture.runAsync(() -> {
            //② 把之前的请求放到不同的线程，这样就能共享之前的请求数据
            RequestContextHolder.setRequestAttributes(requestAttributes);

            //2、远程调用《根据会员 id 查询收货地址》方法
            List<MemberAddressVo> address = memberFeignService.getAddress(memberResponseVo.getId());
            confirmVo.setAddress(address);
        }, executor);

        CompletableFuture<Void> cartFuture = CompletableFuture.runAsync(() -> {
            //② 把之前的请求放到不同的线程，这样就能共享之前的请求数据
            RequestContextHolder.setRequestAttributes(requestAttributes);

            //3、远程调用《获取用户购物车里所有选中的购物项的数据》方法
            List<OrderItemVo> items = cartFeignService.getCurrentUserCartItems();
            confirmVo.setItems(items);
        }, executor).thenRunAsync(() -> {
            //查询库存信息
            List<OrderItemVo> items = confirmVo.getItems();
            List<Long> skuIdsList = items.stream().map(item -> item.getSkuId()).collect(Collectors.toList());

            R hasStock = wmsFeignService.getSkusHasStock(skuIdsList);    //远程调用《根据 skuIds 批量查询商品是否有库存》方法
            List<SkuStockVo> data = hasStock.getData(new TypeReference<List<SkuStockVo>>() {});

            //转成 Map 类型
            if (data != null){
                Map<Long, Boolean> map = data.stream().collect(Collectors.toMap(SkuStockVo::getSkuId, SkuStockVo::getHasStock));
                confirmVo.setStocks(map);
            }
        },executor);

        //4、查询用户积分
        Integer integration = memberResponseVo.getIntegration();
        confirmVo.setIntegration(integration);

        //TODO 防重令牌，幂等性问题
        String token = UUID.randomUUID().toString().replace("-", "");
        //服务器放一份
        stringRedisTemplate.opsForValue().set(
                OrderConstant.USER_ORDER_TOKEN_PREFIX + memberResponseVo.getId(), token, 30, TimeUnit.MINUTES);
        confirmVo.setOrderToken(token);    //页面放一份

        CompletableFuture.allOf(getAddressFuture, cartFuture).get();

        //5、其他数据自动计算
        return confirmVo;
    }

    @Override
    public PageUtils queryPage(Map<String, Object> params) {
        IPage<OrderEntity> page = this.page(
                new Query<OrderEntity>().getPage(params),
                new QueryWrapper<OrderEntity>()
        );
        return new PageUtils(page);
    }


    @Transactional
    public void a(){
        OrderServiceImpl proxy = (OrderServiceImpl) AopContext.currentProxy();
        proxy.b();
        proxy.c();
        int i = 10 / 0;
    }

    //REQUIRED: 如果当前没有事务，就创建新事务，如果当前存在事务，就加入该事务
    @Transactional(propagation = Propagation.REQUIRED)
    public void b(){}

    //REQUIRES_NEW: 创建新事务，无论当前存不存在事务，都创建新事务
    @Transactional(propagation = Propagation.REQUIRES_NEW)
    public void c(){}
}

